package mylab.utils.common.concurrent;

import com.google.common.util.concurrent.ListeningExecutorService;
import com.google.common.util.concurrent.ListeningScheduledExecutorService;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.ThreadFactoryBuilder;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import cn.hutool.core.thread.ExecutorBuilder;

public interface Concurrent {

    int CPU_NUMBER = Runtime.getRuntime().availableProcessors();
    //cpu阻塞系数
    double BLOCK_RATIO = 0.85;

    /**
     * CPU密集型也叫计算密集型，指的是系统的硬盘、内存性能相对CPU要好很多，此时，系统运作大部分的状况是CPU Loading 100%，CPU要读/写I/O(硬盘/内存)，I/O在很短的时间就可以完成，而CPU还有许多运算要处理，CPU Loading 很高。
     * 在多重程序系统中，大部分时间用来做计算、逻辑判断等CPU动作的程序称之CPU bound。例如一个计算圆周率至小数点一千位以下的程序，在执行的过程当中绝大部分时间用在三角函数和开根号的计算，便是属于CPU bound的程序。
     * CPU bound的程序一般而言CPU占用率相当高。这可能是因为任务本身不太需要访问I/O设备，也可能是因为程序是多线程实现因此屏蔽掉了等待I/O的时间。
     * 线程数一般设置为：
     * 线程数 = CPU核数+1 (现代CPU支持超线程)
     */
    int CORE_POOL_SIZE_FOR_CPU = CPU_NUMBER + 1;

    /**
     * IO密集型指的是系统的CPU性能相对硬盘、内存要好很多，此时，系统运作，大部分的状况是CPU在等I/O (硬盘/内存) 的读/写操作，此时CPU Loading并不高。
     * I/O bound的程序一般在达到性能极限时，CPU占用率仍然较低。这可能是因为任务本身需要大量I/O操作，而pipeline做得不是很好，没有充分利用处理器能力
     * 线程数一般设置为：
     * 线程数 = （（线程等待时间+线程CPU时间）/线程CPU时间 ）* CPU数目
     */
    int CORE_POOL_SIZE_FOR_IO = (int) (CPU_NUMBER / (1 - BLOCK_RATIO));

    ExecutorService executor = newCachedThreadPool();
    ScheduledThreadPoolExecutor scheduledExecutor = newScheduledThreadPool(CORE_POOL_SIZE_FOR_IO);
    ListeningExecutorService listeningExecutor = MoreExecutors.listeningDecorator(executor);
    ListeningScheduledExecutorService listeningScheduledExecutor = MoreExecutors.listeningDecorator(scheduledExecutor);

    /**
     * 关闭销毁线程池
     *
     * @param isNow 是否立刻关闭
     */
    static void shutdown(ExecutorService executor, boolean isNow) {
        if (executor == null) {
            return;
        }
        if (isNow) {
            executor.shutdownNow();
        } else {
            executor.shutdown();
        }
    }


    /**
     * 可缓存线程池(无界线程池)
     */
    static ExecutorService newCachedThreadPool() {
        return ExecutorBuilder.create()
                .setCorePoolSize(0)
                .setMaxPoolSize(Integer.MAX_VALUE)
                .setKeepAliveTime(60, TimeUnit.SECONDS)
                .setWorkQueue(new SynchronousQueue<>())
                .build();
    }

    /**
     * 单线程池
     */
    static ExecutorService newSingleThreadPool() {
        return ExecutorBuilder.create()
                .setCorePoolSize(1)
                .setMaxPoolSize(1)
                .setKeepAliveTime(0, TimeUnit.MILLISECONDS)
                .setWorkQueue(new LinkedBlockingQueue<>())
                .build();
    }

    /**
     * 固定线程数线程池
     */
    static ExecutorService newFixedThreadPool(int size) {
        return ExecutorBuilder.create()
                .setCorePoolSize(size)
                .setMaxPoolSize(size)
                .setKeepAliveTime(0, TimeUnit.MILLISECONDS)
                .setWorkQueue(new LinkedBlockingQueue<>())
                .build();
    }

    /**
     * 固定线程数线程池
     */
    static ExecutorService newFixedThreadPool(int corePoolSize, int maxPoolSize) {
        return ExecutorBuilder.create()
                .setCorePoolSize(corePoolSize)
                .setMaxPoolSize(maxPoolSize)
                .setKeepAliveTime(0, TimeUnit.MILLISECONDS)
                .setWorkQueue(new LinkedBlockingQueue<>())
                .build();
    }

    /**
     * 定时调度任务线程池-cpu任务类型场景
     */
    static ScheduledThreadPoolExecutor newScheduledThreadPoolForCpu() {
        return newScheduledThreadPool(CORE_POOL_SIZE_FOR_CPU);
    }

    /**
     * 定时调度任务线程池-IO任务类型场景
     */
    static ScheduledThreadPoolExecutor newScheduledThreadPoolForIO() {
        return newScheduledThreadPool(CORE_POOL_SIZE_FOR_IO);
    }

    /**
     * 定时调度任务线程池
     */
    static ScheduledThreadPoolExecutor newScheduledThreadPool(int corePoolSize) {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("default-scheduled-pool-%d").build();
        return new ScheduledThreadPoolExecutor(corePoolSize, factory);
    }


    /**
     * 创建线程池
     *
     * @param corePoolSize           核心线程数，一旦创建将不会再释放。默认:0
     * @param maxPoolSize            最大池大小（允许同时执行的最大线程数）
     * @param keepAliveTime          线程存活时间，即当池中线程多于初始大小时，多出的线程保留的时长
     * @param keepAliveTimeUnit      keepAlive时间单位
     * @param allowCoreThreadTimeOut 线程执行超时后是否回收线程
     * @param threadFactory          线程工厂，用于自定义线程创建
     * @param rejectedHandler        设置当线程阻塞（block）时的异常处理器，所谓线程阻塞即线程池和等待队列已满，无法处理线程时采取的策略。此处可以使用JDK预定义的几种策略，见RejectPolicy枚举
     * @param workQueue              设置队列，用于存在未执行的线程 可选队列有：<p>
     *                               1. SynchronousQueue    它将任务直接提交给线程而不保持它们。当运行线程小于maxPoolSize时会创建新线程，否则触发异常策略<p>
     *                               2. LinkedBlockingQueue 默认无界队列，当运行线程大于corePoolSize时始终放入此队列，此时maxPoolSize无效。当构造LinkedBlockingQueue对象时传入参数，变为有界队列，队列满时，运行线程小于maxPoolSize时会创建新线程，否则触发异常策略<p>
     *                               3. ArrayBlockingQueue  有界队列，相对无界队列有利于控制队列大小，队列满时，运行线程小于maxPoolSize时会创建新线程，否则触发异常策略<p>
     */
    static ExecutorService newExecutorService(int corePoolSize,
                                              int maxPoolSize,
                                              long keepAliveTime,
                                              TimeUnit keepAliveTimeUnit,
                                              Boolean allowCoreThreadTimeOut,
                                              ThreadFactory threadFactory,
                                              RejectedExecutionHandler rejectedHandler,
                                              BlockingQueue<Runnable> workQueue) {
        return ExecutorBuilder.create()
                .setCorePoolSize(corePoolSize)
                .setMaxPoolSize(maxPoolSize)
                .setAllowCoreThreadTimeOut(allowCoreThreadTimeOut)
                .setKeepAliveTime(keepAliveTime, keepAliveTimeUnit)
                .setWorkQueue(workQueue)
                .setHandler(rejectedHandler)
                .setThreadFactory(threadFactory)
                .build();
    }

    /**
     * 任务队列的长度要根据核心线程数，以及系统对任务响应时间的要求有关。
     * 队列长度可以设置为(corePoolSize/tasktime)*responsetime
     *
     * @param corePoolSize 内核线程数
     * @param tasktime     任务平均执行时间(秒)
     * @param responsetime 系统对的任务响应时间（秒）
     * @return 线程池队长长度
     */
    static int optimalQueueCapacity(int corePoolSize, double tasktime, double responsetime) {
        double n = (corePoolSize / tasktime) * responsetime;
        return (int) n;
    }

}
